package com.ylxin.smartplatform.websocket;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.PongMessage;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author 29048
 * @version V1.0
 * @Project bk2205
 * @Package com.ylxin.smartplatform.websocket
 * @Description: Create by 杨立新 @Date 2022/9/13 11:29
 */

/**
 * 客户端到服务端走http，因为http是短连接，不用websocket长连接造成的内存消耗。降低内存的消耗。
 * 服务端和设备走websocket长连接，并保存设备的标识id保存在服务器，客户端就可以通过服务器之前保存的设备信息来发送数据到设备，当设备挂了等情况都能及时获取信息。
 */

//@Component
//@EnableWebSocket  //开启websocket
public class TestWebsocketIndex1 extends TextWebSocketHandler {

    //服务端和客户端是相对的，客户端发送给另一个客户端，两方的客户端都是me自己，要发送给的另一方叫做toUser要发送给的人。

    //解析正文，有一个ObjectMapper,用来解析json
    private ObjectMapper objectMapper;

    @Autowired
    public void setObject(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    //所有的客户端，保存客户端的map 名字和会话
    private static Map<String, WebSocketSession> allClients = new ConcurrentHashMap<String, WebSocketSession>();

    /**
     * 连接成功之后执行，连接之后我们需要区分是谁。我们做了一个简单的要求，地址的最后一位就是名字，我们用名字进行区分
     * @param session 建立连接成功的会话
     * @throws Exception
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {

        /*
        将连接服务端的客户端数据都保存起来。以提供对应的会话。
         */

        System.err.println("TestWebsocket中的方法afterConnectionEstablished执行了----->");
        String path = session.getUri().getPath();
        //第一必须在地址后面拼上名字。获取用户名，我们约定 最后一个斜杠/后面的就是用户名，有了用户名我们就可以通过Map<String,WebSocketSession>来保存
        String userName = path.substring(path.lastIndexOf("/") + 1);
        //每次单独裁剪取数据比较麻烦，所以我们把数据保存到属性中，方便后面获取
        session.getAttributes().put("name", userName);
        //保存会话，名字对应的会话到一个Map中  连接服务器的名字和它的会话作为一个键值对保存到map中
        allClients.put(userName, session);
    }


    /**
     * 处理文本信息，就是客户端发送了一段文本信息你到服务器
     * @param session  正在发送消息给服务器的会话
     * @param message
     * @throws Exception
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        //把数据取出来/拿到内容也就是拿到正文，然后解析一下 ，正文是一个 json，需要解析。
        String payload = message.getPayload();
        System.err.println("TestWebsocket中的方法handleTextMessage执行了。打印方法中的参数message【载荷/正文】：" + message.getPayload());

        //找到目标接收消息的人的 session ，在某个地方一定 保存了这些session，并且还可以根据zhagnsan，lisi，王五来查询
        //我们怎么知道他想发给谁？（另外一个人也得先连接到服务器，这样我们在Map中才能找到是否有这个用户）
        //  我们约定，发送的 数据格式 是 json ，里面有一个字段代表了接收者的名字，我们用 toUser 来传递数据，msg 代表发送的数据
        //解析json 把payload转为Map.class 就可以把数据放到map中
        Map map = objectMapper.readValue(payload, Map.class);
        //第二，必须发送的数据必须是json数据。toUser 得到接收者，msg内容，我们规定必须toUser  msg 这样来传，有了toUser,只要对方建立连接就会把它保存到map当中
        String toUser = (String) map.get("toUser");  //必须是接收者。
        String msg = (String) map.get("msg");  //必须是消息内容。

        //根据接收者找到对方的会话
        WebSocketSession toSession = allClients.get(toUser);
        //找到名字，保存过所以可以快速取出来。
        Object userName = session.getAttributes().get("name");
        if (toSession != null && toSession.isOpen()) {
            //*****最重要的就是发数据，把消息发送出去，向另一方主动发送数据
            toSession.sendMessage(new TextMessage("收到来自于" + userName + "的消息，内容是：" + msg));
        }else{
            session.sendMessage(new TextMessage("对方不在线"));
        }
    }

    /**
     * 心跳信息，正在发送心跳的会话
     * @param session
     * @param message
     * @throws Exception
     */
    @Override
    protected void handlePongMessage(WebSocketSession session, PongMessage message) throws Exception {
        super.handlePongMessage(session, message);
        System.err.println("TestWebsocket中的方法handlePongMessage执行了");
    }

    /**
     * 当发生异常的时候执行
     * @param session  发生错误的会话
     * @param exception
     * @throws Exception
     */
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        super.handleTransportError(session, exception);
        System.err.println("TestWebsocket中的方法handleTransportError执行了");
    }

    /**
     * 连接关闭之后执行
     * @param session  关闭的会话
     * @param status
     * @throws Exception
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        super.afterConnectionClosed(session, status);
        System.err.println("TestWebsocket中的方法afterConnectionClosed执行了");
    }
}
